﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Noris.Schedule.Support.Services;
using Noris.Schedule.Planning.ProcessData;
using Noris.Schedule.Support;
using Noris.Schedule.Support.Core;
using Noris.Schedule.Support.Green;
using Noris.Schedule.Support.Sql;

namespace Noris.Schedule.Planning.Services
{
	/// <summary>
	/// Třída, která slouží jako správce globálních funkcí plánovací tabule.
	/// Globální funkce jsou vždy přítomny v toolbaru.
	/// </summary>
	internal class FunctionGlobal : IFunctionGlobal
	{
		#region IFunctionGlobal Members
		/// <summary>
		/// Tvorba definic funkcí.
		/// Zde (přes argument) nadefinuji jednotlivé funkce, případně je seskupím do jednoho tlačítka (CreateDropDownButton).
		/// Můžu přidat separátory (CreateSeparator).
		/// Do tlačítek vkládám nějaké functionID, tady vkládám hodnoty typu (enum) DataFunctionType.
		/// Tato hodnota po stisku tlačítka doputuje do metody this.RunToolItem().
		/// </summary>
		/// <param name="args"></param>
		void IFunctionGlobal.CreateToolItem(FunctionGlobalCreateArgs args)
		{
			string fileName = System.IO.Path.Combine(Steward.ExecutablePath, "IsTestEnv.info");
			bool isForTests = System.IO.File.Exists(fileName);
			isForTests = false;


			if (isForTests)
			{
				args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.DataRefresh, PicLibrary32.Reload_32_FromFile, "Znovu načte veškerá data z databáze"));
				args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.DataLoad, PicLibrary32.Folder_refresh_32_FromFile, "Načte data plánu z databáze"));

                if (!Steward.RunReadOnly)
                {
                    // Varianty plánovacího procesu:
                    this._FindPlanVariations(args);

                    //args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.PlanCreateNew, PicLibrary32.Spreadsheet_32_FromFile, "Spustí celý proces plánování pro aktuální verzi plánu"));
                    args.AddItem(FunctionGlobalItem.CreateDropDownButton(this, DataFunctionType.PlanCreateNew, PicLibrary32.Spreadsheet_32_FromFile, "Spustí celý proces plánování pro aktuální verzi plánu",
                                 FunctionGlobalItem.CreateButton(this, DataFunctionType.PlanCreateNew, PicLibrary22.Documentpagesetup_FromFile /* PicLibrary22.Alignhorizontalright2_FromFile */, "Nový plán", "Vytvoří celý nový plán. Zahodí vše kromě fixovaných položek, a začne plánovat od nuly."),
                                 FunctionGlobalItem.CreateButton(this, DataFunctionType.PlanForwardAll, PicLibrary22.Alignhorizontalleft2_FromFile, "Přeplánuj dopředně", "Přeplánuje dopředně vše nefixované. Žádná operace nezačne před aktuálním datem. Některé zakázky se možná nestihnou dokončit v termínu."),
                                 FunctionGlobalItem.CreateButton(this, DataFunctionType.PlanUnfixed, PicLibrary22.Alignverticaltop2_FromFile, "Přeplánuj nefixované úkoly", "Přeplánuje nefixované úkoly")
                                 ));

                    args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.DataSave, PicLibrary32.Floppy_disc_down_32_FromFile, "Uloží data aktuální verze plánu do databáze"));
                }

				args.AddItem(FunctionGlobalItem.CreateSeparator());
				args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.PlanningConfig, PicLibrary32.Colorize2_FromFile, "Nastavení parametrů procesu"));
			}
			else
			{
				args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.DataRefresh, PicLibrary32.Reload_32_FromFile, "Znovu načte veškerá data z databáze"));
				args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.DataLoad, PicLibrary32.Folder_refresh_32_FromFile, "Načte data plánu z databáze"));

                if (!Steward.RunReadOnly)
                {
                    // Varianty plánovacího procesu:
                    this._FindPlanVariations(args);
                    args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.PlanCreateNew, PicLibrary32.Spreadsheet_32_FromFile, "Spustí celý proces plánování pro aktuální verzi plánu"));
                    args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.PlanUnfixed, PicLibrary22.Alignverticaltop2_FromFile, "Přeplánuj nefixované úkoly"));
                    args.AddItem(FunctionGlobalItem.CreateButton(this, DataFunctionType.DataSave, PicLibrary32.Floppy_disc_down_32_FromFile, "Uloží data aktuální verze plánu do databáze"));
                }
			}
		}
		/// <summary>
		/// Provedení funkce poté, kdy si ji uživatel vybral
		/// </summary>
		/// <param name="args"></param>
		void IFunctionGlobal.RunToolItem(FunctionGlobalRunArgs args)
		{
            // FunctionID může být Type třídy, která je variantou plánovacího procesu (viz this._FindPlanVariations()):
            VariationID variationID;
            if (args.TryGetFunctionID<VariationID>(out variationID))
            {
                this._RunToolPlanVariationPlugin(args, variationID);
                return;
            }

            // FunctionID může být enum DataFunctionType, který identifikuje výkonnou funkci:
			DataFunctionType functionId;
            if (args.TryGetFunctionID<DataFunctionType>(out functionId))
            {
                this._RunToolFunction(args, functionId);
                return;
            }
		}
        /// <summary>
        /// Zajistí spuštění funkce identifikované její hodnotou functionId
        /// </summary>
        /// <param name="args"></param>
        /// <param name="functionId"></param>
        private void _RunToolFunction(FunctionGlobalRunArgs args, DataFunctionType functionId)
        {
            switch (functionId)
            {	// Některé funkce řeším zde:
                case DataFunctionType.PlanningConfig:
                    _RunToolFunctionConfig(args, functionId);
                    break;

                // Ostatní funkce pošlu do našeho datového zdroje:
                default:
                    args.ResultCallDataSourceRequest = true;
                    args.ResultCallRequestData = args.RunItem.FunctionID;              // Předám ID funkce (což je aktuálně typ DataFunctionType) do dat RequestData pro požadavek do datového zdroje
                    args.ResultCallDataSourceOfType = null;                            // Požadavek předat jen do tohoto zdroje. Může zde být null, pak se předá do všech zdrojů.
                    break;
            }
        }
		#endregion
        #region TESTY
        private void _RunToolFunctionConfig(FunctionGlobalRunArgs args, DataFunctionType functionId)
        {
            IDataSource planningSource = args.TryGetExternalDataSource(typeof(MfrPlanningConnectorCls));

            string sql;
            FilterInfo f;

            sql = _getSelect0();
            using (SqlText sqlText = SqlText.CreateFromText(sql))          // Převedu text do parsované podoby, kde s ním lze čarovat
            {
                SqlParseCommandSelect sqlSel = (SqlParseCommandSelect)sqlText.FindFirstCommand("SELECT");
                SqlParseSyntaxItem syntW;

                f = Repository.Filters[516];      // Poptávka
                f.AddExpressionToBegin(1, "lcs.sk_hlavicka.typ", "lcs.sk_hlavicka.typ = '4'", "AND");
                f.ApplyFilterToSqlCommand(sqlSel);
                syntW = sqlSel.SyntaxFind("WHERE");
                string where3 = syntW.SqlContentCurrent;     // Filtr
                syntW.Deactivate();                          // Odstranit filtr z commandu.

                f = Repository.Filters[846];      // Objednávka
                f.AddExpressionToBegin(1, "lcs.sk_hlavicka.typ", "lcs.sk_hlavicka.typ = '3'", "AND");
                f.ApplyFilterToSqlCommand(sqlSel);
                syntW = sqlSel.SyntaxFind("WHERE");
                string where4 = syntW.SqlContentCurrent;     // Filtr
                syntW.Deactivate();                          // Odstranit filtr z commandu.


                string where0 = "p.pocet > p.pocet_real and skl.planovat = 'A' AND p.splneno_uziv = 'N'";
                string where = "(" + where0 + ") AND ((" + where3 + ") OR (" + where4 + "))";
                syntW.AddSyntaxExpression(where);

                sql = sqlText.OutputSqlText;

                // sqlSel.SyntaxItemsUsed


            }


            sql = _getSelect2();

            f = FilterInfo.CreateForClass(1188);
            f.AddExpressionToBegin(1, "lcs.product_order.status", "lcs.product_order.status = 'A'", "AND");
            f.ApplyFilterToSelect(ref sql);


            sql = _getSelect2();
            f = Repository.Filters[951];
            f.AddExpressionToBegin(1, "lcs.product_order.qty", "{{Alias}}.status = 'A' and {{Alias}}.qty >= 10", "AND");
            f.ApplyFilterToSelect(ref sql);



            sql = _getSelect2();
            Repository.Filters.ApplyFilterToSelect(951, ref sql);

            sql = _getSelect1();
            int filtRV = 516;  // realita výroby
            Repository.Filters.ApplyFilterToSelect(filtRV, ref sql);

            if (false)
            {

                sql = "SELECT po.* FROM lcs.product_order po";
                Repository.Filters.ApplyFilterToSelect(951, ref sql);







                string filter = Repository.Filters.GetSelect(951);

                var tem = Repository.Templates[11206];

                RelationInfo relation = Repository.Relations[8909];     // Výrobní příkaz => Sklad pro odvedení
                var folders = relation.FoldersList;
                int fldCnt = folders.Count;

                ClassInfo ci = Repository.Classes[1188];
                ClassInfo ci2 = Repository.Classes[11880];
                List<RelationInfo> relList = Repository.Classes[1180].RelationLeftList;

                FilterInfo fi = Repository.Filters[314];


                Dialog.ShowWarning("Není to ještě hotové.");
                /*
                Throw.AplError("Není to hotové ani teď.");
                 */

            }
        }
        private string _getSelect0()
        {
            return @"SELECT 
  p.cislo_subjektu,
  p.cislo_objektu,
  p.cislo_radky,
  f.cislo_tridy,
  cast(1 as int) as data_type,
  p.zdroj source,
  isnull(skl.sklad_mrp,skl.cislo_subjektu) stock,
  p.varianta_zbozi variation,
  p.obchodni_pripad order_relation,
  p.typ,
  p.pocet qty,
  p.pocet_real as qty_realized,
  p.datum date,
  p.datum_plan date_plan,
  p.referencni_cislo reference_number,
  h.sklad2 sklad2,
  f.cislo_poradace,
  f.nazev as folder_nazev,
  h.reference_subjektu,
  h.nazev_subjektu,
  h.organizace,
  org.reference_subjektu as organizace_refer,
  org.nazev_subjektu as organizace_nazev,
  (select top 1 cislo_objektu from lcs.sk_polozka n where n.pohyb_polozka = p.cislo_objektu and (n.stav = 1 and n.typ = '4' /* and (n.pocet - n.pocet_real) > 0 and n.splneno_uziv = 'N' */ )) as vnitropoptavka 
FROM #mrp_item itm 
  JOIN lcs.sk_polozka p ON p.cislo_objektu = itm.cislo_objektu
  JOIN lcs.sk_hlavicka h ON h.cislo_subjektu = p.cislo_subjektu
  JOIN lcs.poradace f ON f.cislo_poradace = h.cislo_poradace
  JOIN lcs.sk_sklad skl ON p.sklad=skl.cislo_subjektu
  LEFT OUTER JOIN lcs.subjekty org ON org.cislo_subjektu = h.organizace";
        }
        private string _getSelect1()
        {
            return @"SELECT 
  p.cislo_subjektu,
  p.cislo_objektu,
  p.cislo_radky,
  f.cislo_tridy,
  cast(1 as int) as data_type,
  p.zdroj source,
  isnull(skl.sklad_mrp,skl.cislo_subjektu) stock,
  p.varianta_zbozi variation,
  p.obchodni_pripad order_relation,
  p.typ,
  p.pocet qty,
  p.pocet_real as qty_realized,
  p.datum date,
  p.datum_plan date_plan,
  p.referencni_cislo reference_number,
  h.sklad2 sklad2,
  f.cislo_poradace,
  f.nazev as folder_nazev,
  h.reference_subjektu,
  h.nazev_subjektu,
  h.organizace,
  org.reference_subjektu as organizace_refer,
  org.nazev_subjektu as organizace_nazev,
  (select top 1 cislo_objektu from lcs.sk_polozka n where n.pohyb_polozka = p.cislo_objektu and (n.stav = 1 and n.typ = '4' /* and (n.pocet - n.pocet_real) > 0 and n.splneno_uziv = 'N' */ )) as vnitropoptavka 
FROM #mrp_item itm 
  JOIN lcs.sk_polozka p ON p.cislo_objektu = itm.cislo_objektu
  JOIN lcs.sk_hlavicka h ON h.cislo_subjektu = p.cislo_subjektu
  JOIN lcs.poradace f ON f.cislo_poradace = h.cislo_poradace
  JOIN lcs.sk_sklad skl ON p.sklad=skl.cislo_subjektu
  LEFT OUTER JOIN lcs.subjekty org ON org.cislo_subjektu = h.organizace
WHERE p.pocet > p.pocet_real and skl.planovat = 'A' AND p.splneno_uziv = 'N'
ORDER BY p.cislo_objektu";
        }
        /// <summary>
        /// 
        /// </summary>
        private string _getSelect2()
        {
            return @"SELECT
 s.reference_subjektu,
 s.nazev_subjektu,
 po.qty,
 po.status,
 po.a_operation_mod,
 poc.qty_real,
 poc.date_event,
 poc.price1,
 opr.real_time,
 poo.op_name
FROM lcs.subjekty s
left outer join lcs.product_order_costs poc on poc.product_order = s.cislo_subjektu
join lcs.product_order po on po.cislo_subjektu = s.cislo_subjektu
left outer join lcs.operation_report opr on opr.product_order = poc.product_order
left outer join lcs.product_order_operation poo on poo.product_order = s.cislo_subjektu";
        }
        #endregion
        #region VARIANTY PLÁNU
        /// <summary>
        /// Metoda najde a do argumentu doplní varianty plánovacího procesu.
        /// </summary>
        /// <param name="args"></param>
        private void _FindPlanVariations(FunctionGlobalCreateArgs args)
        {
            List<FunctionGlobalItem> varItems = PlanVariatorManager.GetVariationItems(this);
            if (varItems.Count > 0)
                args.AddItem(FunctionGlobalItem.CreateComboBox(this, "Výběr variant plánovacího procesu", true, varItems));
        }
        /// <summary>
        /// Zajistí aktivaci pluginu typu 
        /// </summary>
        /// <param name="args"></param>
        /// <param name="variationID"></param>
        private void _RunToolPlanVariationPlugin(FunctionGlobalRunArgs args, VariationID variationID)
        {
            PlanVariatorManager.SetCurrentVariation(variationID);
        }
        #endregion
    }
}
